class h_sys {

	// async getStuPhoto(stuId, user) {
	// 	const stuData = await this.hd.user.getStuDataByStuId(stuId, 'stuPhoto')
	// 	const result = await this.common.reqGet({
	// 		url: `${this.config.zf.url}${stuData.stuPhoto}`,
	// 	})
	// 	console.log(result)
	// }

	// async handler() {
	// 	let data = await this.mysql.cxxy.select({
	// 		table: 'student',
	// 		field: [
	// 			'stuId',
	// 			'stuIdCard'
	// 		]
	// 	})
	// 	await this.mysql.cxxy.trans()
	// 	for(let {stuId, stuIdCard} of data) {
	// 		 await this.mysql.cxxy.update({
	// 			table: 'student',
	// 			field: [
	// 				'stuPwd=$stuIdCard'
	// 			],
	// 			where: 'stuId=$stuId',
	// 			data: {
	// 				stuId,
	// 				stuIdCard
	// 			}
	// 		})
	// 	}
	// 	await this.mysql.cxxy.cmt()
	// }

	async getAppInfo(appId, ...fields) {
		return await this._getAppInfo(appId, ...fields)
	}

	async encryptTableData(table, field = [], where = '') {
		field.push(where)
		const data = await this.mysql.cxxy.select({
			table,
			field
		})
		field.splice(field.indexOf(where), 1)
		let updateField = []
		for(let index in field) {
			updateField[index] = `${field[index]}=$${field[index]}`
		}
		for(let d of data) {
			let tmp = {}
			for(let f of field)  {
				if(d[f])
					tmp[f] = await this.mysql.cxxy.encryptData(d[f])
				else
					tmp[f] = ''
			}
			console.log(tmp)
			await this.mysql.cxxy.update({
				table,
				field: updateField,
				data: tmp,
				where: `${where}='${d[where]}'`
			})
		}
	}

	async getCommonData(...fields) {
		return await this._getCommonData(...fields)
	}

	async getBanners() {
		const result = await this._getCommonData('banners')
		if(!result.banners)
			return []
		return result.banners
	}

	async getNotices(noticeId) {
		const result = await this._getCommonData('noticeId', 'notices')
		if(!noticeId) {
			if(!result || !result.notices)
				return this.reject('-2036', 'get notices failed')
			return {
				notices: result.notices
			}
		}
		if(noticeId == result.noticeId)
			return {}
		return {
			noticeId: result.noticeId,
			notices: result.notices
		}
	}

	async getCourseTermInfo() {
		return await this._getCommonData('courseYear', 'courseTerm')
	}

	async getOSSData() {
		let date = new Date()
		date.setHours(date.getHours() + 1)
		const policyText = {
			expiration: date.toISOString(),
			conditions: [
				["content-length-range", 0, 1048576000]
			]
		}
		const policy = this.crypto.encodeBase64(JSON.stringify(policyText))
		return {
			accessKeyId: this.config.oss.accessKeyId,
			policy,
			signature: this.crypto.encryptHMAC(policy, this.config.oss.accessKeySecret)
		}
	}

	async getRepairTypes() {
		const result = await this._getCommonData('repairTypes')
		if(!result.repairTypes)
			return []
		return result.repairTypes
	}

	async addFeedback(userId, content, contact) {
		if(!userId)
			return this.reject('-2034', 'feedback user id invalid')
		if(!content || content.length > 255)
			return this.reject('-2032', 'feedback content invalid')
		if(!contact || contact.length > 120)
			return this.reject('-2033', 'feedback contact invalid')
		if(!/^([a-zA-Z][-_a-zA-Z0-9]{5,19})|(1[3-9]\d{9})$/.test(contact) && !/^1[3-9]\d{9}$/.test(contact))
			return this.reject('-2033', 'feedback contact invalid')
		const feedbackId = await this.crypto.md5(userId + content + contact)
		const result = await this.mysql.cxxy.select({
			table: 'feedback',
			field: 'feedbackId',
			where: 'feedbackId=$feedbackId',
			data: {
				feedbackId
			}
		})
		if(result[0])
			return this.reject('-2035', 'feedback is exists')
		await this.mysql.cxxy.insert({
			table: 'feedback',
			field: [
				'feedbackId',
				'feedbackUser',
				'feedbackContent',
				'feedbackContact',
				'feedbackDate'
			],
			data: {
				feedbackId,
				feedbackUser: userId,
				feedbackContent: content,
				feedbackContact: contact,
				feedbackDate: parseInt(Date.now() / 1000)
			}
		})
		return feedbackId
	}

	async pushAllMessage(msgType, msgData) {

	}

	async pushUserMessage(senderUser, userId, msgType, msgData = {}) {
		const ch = await this.amqp.message.createChannel()
		const msgId = await this.common.createRandomStr(32)
		ch.send(`student@${userId}`, this._parseData(msgId, msgType, msgData))
		//非重要消息不备份到数据库
		await this._addMsgData(senderUser, userId, msgId, msgType, msgData)
	}

	async pushStuMessage(senderUser, stuId, msgType, msgData = {}) {
		const stuData = await this.hd.student.getStuDataByStuId(stuId, 'userId', 'stuName')
		if(!stuData)
			return this.reject('-2009', 'student not found')
		const {userId} = stuData
		console.log('学生用户', stuData)
		const ch = await this.amqp.message.createChannel()
		const msgId = await this.common.createRandomStr(32)
		ch.send(`student@${userId}`, this._parseData(msgId, msgType, msgData))
		//非重要消息不备份到数据库
		await this._addMsgData(senderUser, userId, msgId, msgType, msgData)
	}

	async pushTchMessage(tchId, msgType, msgData = {}) {

	}

	async getMsgDataByMsgId(msgId, ...fields) {
		let msgData = {}
		const index = fields.indexOf('msgData')
		if(index != -1)
			fields.splice(index, 1)
		console.log(fields)
		let msg = await this.mysql.cxxyMsg.select({
			table: 'msg_index',
			field: fields || ['msgType', 'msgSender', 'msgReceiver', 'msgStatus', 'msgDate'],
			where: 'msgId=$msgId',
			data: {
				msgId
			}
		})
		if(!msg[0])
			return null
		msgData = msg[0]
		if(msgData.msgType)
			msgData.msgType = await this._msgTypeMapper(msgData.msgType)
		if(index != -1) {
			const tableIndex = this.common.hashTableIndex(msgId)
			const temp = await this.mysql.cxxyMsg.select({
				table: `msg_${tableIndex}`,
				field: 'msgData',
				where: 'msgId=$msgId',
				data: {
					msgId
				}
			})
			if(!temp[0])
				return this.reject('-2056', 'message index map data not found')
			msgData.msgData = this.common.isJson(temp[0].msgData)
			if(!msgData.msgData)
				return this.reject('-2058', 'message data parse error')
		}
		return msgData
	}

	async updateMsgStatus(msgId, msgStatus) {
		if([0,1,2].indexOf(msgStatus) == -1)
			return this.reject('-2048', 'message status invalid')
		await this.mysql.cxxyMsg.update({
			table: 'msg_index',
			field: 'msgStatus=$msgStatus',
			where: 'msgId=$msgId',
			data: {
				msgStatus,
				msgId
			}
		})
	}

	async assertMsgData(data, ...keys) {
		for(let k of keys) {
			if(!data[k] && data[k] !== 0)
				return this.reject('-2049', 'push message data invalid')
		}
	}

	async getGrabCourseByMajorId(majorId) {
		if(!this._checkMajorId(majorId))
			return this.reject('-3026', 'major id is invalid')
		const grabCourseData = await this._getGrabCourseByMajorId(majorId)
		return grabCourseData
	}

	async updateGrabCourses(grabCourseType = 0, grabCourseList = [], grabCourseMajor, grabCourseGrade) {
		for(let grabCourse of grabCourseList) {
			if(!this._checkMajorId(grabCourseMajor))
				return this.reject('-3026', 'major id is invalid')
			if(!this._checkLongGrade(grabCourseGrade))
				return this.reject('-2073', 'long grade id invalid')
			const {courseName, courseTid, courseTch, courseTimeList, courseRoom, courseCount, courseData} = grabCourse
			if(courseTimeList.length == 0)
				courseTimeList = [{startWeek: -1, endWeek: -1, doubleWeek: -1, day: -1, pitch: -1}]
			for(let courseTime of courseTimeList) {
				for(let tch of courseTch) {
					const {startWeek, endWeek, doubleWeek, day, pitch} = courseTime
					const courseId = this.crypto.md5(grabCourseMajor + grabCourseGrade + courseTid + courseName + tch + startWeek + endWeek + doubleWeek + day + pitch)
					const roomId =  await this.hd.department.addClassroom(courseRoom)
					const result = await this.mysql.cxxy.select({
						table: 'grab_course',
						field: 'courseName',
						where: 'courseId=$courseId',
						data: {
							courseId
						}
					})
					let _result = 0
					if(result[0]) 
						_result = await this.mysql.cxxy.update({
							table: 'grab_course',
							field: [
								'courseType=$courseType',
								'courseGrade=$courseGrade',
								'courseTid=$courseTid',
								'courseName=$courseName',
								'courseTch=$courseTch',
								'courseDay=$courseDay',
								'coursePitch=$coursePitch',
								'majorId=$majorId',
								'roomId=$roomId',
								'startWeek=$startWeek',
								'endWeek=$endWeek',
								'doubleWeek=$doubleWeek',
								'courseCount=$courseCount',
								'courseData=$courseData'
							],
							where: 'courseId=$courseId',
							data: {
								courseType: grabCourseType,
								courseGrade: grabCourseGrade,
								courseTid,
								courseName,
								courseTch: tch,
								courseDay: day,
								coursePitch: pitch.join(','),
								majorId: grabCourseMajor,
								roomId,
								startWeek,
								endWeek,
								doubleWeek, 
								courseCount,
								courseData: JSON.stringify(courseData),
								courseId
							}
						})
					else
						_result = await this.mysql.cxxy.insert({
							table: 'grab_course',
							field: [
								'courseId',
								'courseType',
								'courseGrade',
								'courseTid',
								'courseName',
								'courseTch',
								'courseDay',
								'coursePitch',
								'majorId',
								'roomId',
								'startWeek',
								'endWeek',
								'doubleWeek',
								'courseCount',
								'courseData'
							],
							data: {
								courseId,
								courseType: grabCourseType,
								courseGrade: grabCourseGrade,
								courseTid,
								courseName,
								courseTch: tch,
								courseDay: day,
								coursePitch: pitch.join(','),
								majorId: grabCourseMajor,
								roomId,
								startWeek,
								endWeek,
								doubleWeek,
								courseCount,
								courseData: JSON.stringify(courseData)
							}
						})
					if(_result == 0)
						return this.reject('-3024', 'sync grab course data failed')
				}
			}
		}
		if(grabCourseType == 0)
			await this.redis.grab.delete(`courses@${grabCourseGrade}@${grabCourseMajor}`)
		else
			await this.redis.grab.delete(`sportsCourses@${grabCourseGrade}@${grabCourseMajor}`)
	}

	async getFeedbackList() {
		return await this.mysql.cxxy.select({
			table: 'feedback',
			field: [
				'feedbackId',
				'feedbackContent',
				'feedbackContact',
				'feedbackFinish',
				'feedbackDate'
			],
			sort: {
				field: 'feedbackDate',
				order: 'desc'
			},
			limit: 15
		})
	}

	async _getAppInfo(appId, ...fields) {
		const result = await this.mysql.cxxy.select({
			table: 'app_info',
			field: fields,
			where: 'appId=$appId',
			data: {
				appId
			}
		})
		if(!result[0])
			return this.reject('-2107', 'app info not found')
		return result[0]
	}

	async _getGrabCourseByMajorId(majorId) {
		let grabCourseData = await this.redis.grab.get(`courses@${majorId}`, true)
		if(!grabCourseData) {
			grabCourseData = await this.mysql.cxxy.select({
				table: [
					'grab_course g',
					'classroom r'
				],
				field: [
					'courseId',
					'courseType',
					'courseTid',
					'courseName',
					'courseTch',
					'courseDay',
					'coursePitch',
					'courseData',
					'majorId',
					'g.roomId',
					'startWeek',
					'endWeek',
					'doubleWeek',
					'startTime',
					'endTime',
					'courseCount',
					'roomName'
				],
				where: 'courseType=0 && endTime>=$nowTime && majorId=$majorId && g.roomId=r.roomId',
				data: {
					nowTime: parseInt(Date.now() / 1000),
					majorId
				}
			})
			await this.redis.grab.set(`courses@${majorId}`, grabCourseData)
			console.log('refresh redis grab course list')
		}
		return grabCourseData
	}

	async _msgTypeMapper(msgType) {
		if(isNaN(msgType)) {
			const type = this.config.frame.msgType.indexOf(msgType)
			console.log(msgType, type)
			if(type == -1)
				return this.reject('-2055', 'message type invalid')
			return type + 1
		}
		else {
			const type = this.config.frame.msgType[msgType]
			if(!type)
				return this.reject('-2055', 'message type invalid')
			return type
		}
	}

	async _addMsgData(senderUser = '', receiverUser = '', msgId = -1, msgType = '', msgData = {}) {
		console.log(senderUser, '啊啊啊', receiverUser)
		if(!senderUser || !receiverUser)
			return this.reject('-2050', 'message user id invalid')
		if(msgId.length != 32)
			return this.reject('-2051', 'message id invalid')
		const tableIndex = this.common.hashTableIndex(msgId)
		await this.mysql.cxxy.trans()
		await this.mysql.cxxyMsg.createTable({
			table: `msg_${tableIndex}`,
			field: [
				"`Id` int(11) NOT NULL AUTO_INCREMENT",
				"`msgId` varchar(32) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '消息ID'",
				"`msgData` text COLLATE utf8mb4_bin NOT NULL COMMENT '消息数据'",
				"PRIMARY KEY (`Id`)",
				"UNIQUE KEY `msgId` (`msgId`)"
			],
			attr: {
				autoId: true,
				comment: `创新盒子消息表${tableIndex}`
			}
		})
		//转换消息类型
		msgType = await this._msgTypeMapper(msgType)
		await this.mysql.cxxyMsg.insert({
			table: `msg_${tableIndex}`,
			field: [
				'msgId',
				'msgData'
			],
			data: {
				msgId,
				msgData: JSON.stringify(msgData)
			}
		})
		await this.mysql.cxxyMsg.insert({
			table: 'msg_index',
			field: [
				'msgId',
				'msgType',
				'msgSender',
				'msgReceiver',
				'msgDate'
			],
			data: {
				msgId,
				msgType,
				msgSender: senderUser,
				msgReceiver: receiverUser,
				msgDate: parseInt(Date.now() / 1000)
			}
		})
		await this.mysql.cxxy.cmt()
	}

	_parseData(id, type, data) {
		return JSON.stringify({
			id,
			type,
			data,
			time: parseInt(Date.now() / 1000)
		})
	}

	async _getCommonData(...fields) {
		let commonData = await this.redis.system.get('commonData', true)
		if(!commonData) {
			commonData = await this.mysql.cxxy.select({
				table: 'common',
				field: ['infoName', 'infoValue'],
				where: `infoName in ('${fields.join(`','`)}')`
			})
			let temp = {}
			for(let data of commonData) {
				temp[data.infoName] = data.infoValue
			}
			commonData = temp
			await this.redis.system.set('commonData', commonData)
		}
		else {
			const keys = Object.keys(commonData)
			const noFields = fields.filter((key) => {
				return keys.indexOf(this.common.trim(key)) == -1
			})
			if(noFields.length != 0) {
				let result = await this.mysql.cxxy.select({
					table: 'common',
					field: ['infoName', 'infoValue'],
					where: `infoName in ('${noFields.join(`','`)}')`
				})
				if(result[0]) {
					let temp = {}
					for(let data of result) {
						temp[data.infoName] = data.infoValue
					}
					Object.assign(commonData, temp)
				}
				await this.redis.system.set('commonData', commonData)
			}
		}
		let data = {}
		for(let k of fields) {
			const temp = this.common.isJson(commonData[k])
			data[k] = temp ? temp : commonData[k]
		}
		commonData = data
		return commonData ? commonData : null
	}

	_checkMajorId(majorId) {
		return /^[a-z0-9]{32}$/.test(majorId)
	}

	_checkLongGrade(grade) {
		return /^\d{4}$/.test(grade)
	}

}

module.exports = h_sys